package com.friends.common.web.interceptor;

import com.friends.common.tools.constant.AppKey;
import com.friends.common.tools.util.Tools;
import com.friends.common.web.annotation.SignValid;
import com.friends.common.web.exception.SignvalidException;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * 参数验签拦截器
 * （1）	拼接待签名参数字符串
 *     appid串+ 业务参数字典序串+appsecret串+timestamp参数值串
 *     业务参数字典序串拼接规则：按字典排序后使用形式(参数名+参数值)进行拼接
 * （2）	对拼接待签名参数字符串进行MD5签名获得sign值串
 * （3）	需传递参数包括：appid、业务参数、timestamp、sign
 * （4）	在需要验签的方法上使用SignValid注解，形如：
 *      @SignValid(signfileds={“业务参数1”,” 业务参数2”})
 *
  * Created by xiajiangge on 2017/2/24.
 */
public class SignvalidInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod)handler;
            Method method = handlerMethod.getMethod();
            SignValid annotation = method.getAnnotation(SignValid.class);
            //有无注解，是否验证签名
            if (annotation == null) return true;
            //获取需要验证签名的字段
            String[] signfileds = annotation.signfileds();
            //没有则不验证
            if(signfileds.length < 1 ) return true;
            //获取用户提交的签名
            String user_sign = request.getParameter("sign");
            if(StringUtils.isEmpty(user_sign)){
                throw new SignvalidException("没有签名参数");
            }
            //获取用户提交的APPID
            String user_appid = request.getParameter("appid");
            if(StringUtils.isEmpty(user_appid)){
                throw new SignvalidException("没有appid参数");
            }
            //获取用户提交的timestamp
            String timestamp = request.getParameter("timestamp");
            if(StringUtils.isEmpty(timestamp)){
                throw new SignvalidException("没有timestamp参数");
            }
            long timestamp_l = Long.parseLong(timestamp);
            long timestamp_c = System.currentTimeMillis();
            if((timestamp_c - timestamp_l) > 300000){
                throw new SignvalidException("请校对设备时间");
            }
            String appsecret = "";
            //提取appid对应secret
            for(AppKey ak : AppKey.values()){
                String id = ak.getId();
                if(id.equals(user_appid)){
                    appsecret = ak.getSecret();
                }
            }
            if(StringUtils.isEmpty(appsecret)){
                throw new SignvalidException("appid参数无效");
            }
            //有该注解需要验证参数签名
            //参数名按字母顺序升排序
            List<String> filedList = Arrays.asList(signfileds);
            Collections.sort(filedList);
            //取出各参数值拼接成待验签字符串
            StringBuffer waitValidStr = new StringBuffer(user_appid);
            for(String filed : filedList){
                String value = request.getParameter(filed);
                waitValidStr.append(filed).append(value);
            }
            waitValidStr.append(appsecret);
            waitValidStr.append(timestamp);
            //对串进行签名
            String sys_sign = Tools.MD5(waitValidStr.toString());
            if(!sys_sign.equals(user_sign)){
                throw new SignvalidException("参数签名错误");
            }
            return true;
        } else {
            return super.preHandle(request,response,handler);
        }
    }


}
